#include "services.h"
#include "rtthread.h"

#include "ch32v30x_rcc.h"
#include "ch32v30x_gpio.h"
#include "ch32v30x_usart.h"

static uint8_t p_us = 0;
static uint16_t p_ms = 0;

uint32_t SystemCoreClock = 144000000;

void Sys_delayInit(void){
    p_us = SystemCoreClock / 8000000;
    p_ms = (uint16_t)p_us * 1000;
}

void Sys_delayUs(uint32_t nus){
    uint32_t i;
    SysTick->SR &= ~(1 << 0);
    i = (uint32_t)nus * p_us;
    SysTick->CMP = i;
    SysTick->CTLR |= (1 << 4);
    SysTick->CTLR |= (1 << 5) | (1 << 0);
    while ( (SysTick->SR & (1 << 0)) != (1 << 0) );
    SysTick->CTLR &= ~(1 << 0);
}

void Sys_delayMs(uint32_t nms){
    uint32_t i;
    SysTick->SR &= ~(1 << 0);
    i = (uint32_t)nms * p_ms;
    SysTick->CMP = i;
    SysTick->CTLR |= (1 << 4);
    SysTick->CTLR |= (1 << 5) | (1 << 0);
    while( (SysTick->SR & (1 << 0)) != (1 << 0) );
    SysTick->CTLR &= ~(1 << 0);
}

/* 移植按需修改 */
__attribute__((weak))
void Printf_init(void){
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA,&GPIO_InitStructure);
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_Mode = USART_Mode_Tx;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_Init(USART1,&USART_InitStructure);
    USART_Cmd(USART1,ENABLE);
}

__attribute__((used)) int _write(int fd,char *buf,int size){
    int i;
    for ( i = 0; i < size; i++ ){
        while ( USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET );
        USART_SendData(USART1,*buf++);
    }
    return size;
}

void *_sbrk(ptrdiff_t incr){
    extern char _end[];
    extern char _heap_end[];
    static char *curbrk = _end;

    if ( (curbrk + incr < _end) || (curbrk + incr > _heap_end) )
    return NULL - 1;

    curbrk += incr;
    return curbrk - incr;    
}

__attribute__((interrupt("WCH-Interrupt-fast")))
void NMI_Handler(void){
    GET_INT_SP();
    rt_interrupt_enter();
    rt_kprintf("NMI Handler\r\n");
    rt_interrupt_leave();
    FREE_INT_SP();
}

__attribute__((interrupt("WCH-Interrupt-fast")))
void HardFault_Handler(void){
    GET_INT_SP();
    rt_interrupt_enter();
    rt_kprintf("HardFault occured\r\n");
    rt_interrupt_leave();
    FREE_INT_SP();
}

void Sys_setClock(void){
    /* 启用HSE */
    __IO uint32_t  StartUpCounter = 0, HSEStatus = 0;
    RCC->CTLR |= ((uint32_t)RCC_HSEON);
    do{
        HSEStatus = RCC->CTLR & RCC_HSERDY;
        StartUpCounter++;
    }while ( (HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT) );
    if ( (RCC->CTLR & RCC_HSERDY) != RESET ){
        HSEStatus = (uint32_t)0x01;
    }else{
        HSEStatus = (uint32_t)0x00;
    }

    if ( HSEStatus == (uint32_t)0x01 ){
        RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
        RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
        RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV1;
        RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
        RCC->CFGR0 |= (uint32_t)RCC_SW_HSE;
        while ( (RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x04 );
    }else{
        /* HSE启动失败的处理 */
        return;
    }
    /* 配置时钟至144MHz */
    RCC->CTLR |= ((uint32_t)RCC_HSEON);
    do{
        HSEStatus = RCC->CTLR & RCC_HSERDY;
        StartUpCounter++;
    }while ( (HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

    if ( (RCC->CTLR & RCC_HSERDY) != RESET){
        HSEStatus = (uint32_t)0x01;
    }else{
        HSEStatus = (uint32_t)0x00;
    }

    if ( HSEStatus == (uint32_t)0x01 ){
        RCC->CFGR0 |= (uint32_t)RCC_HPRE_DIV1;
        RCC->CFGR0 |= (uint32_t)RCC_PPRE2_DIV1;
        RCC->CFGR0 |= (uint32_t)RCC_PPRE1_DIV2;
        RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_PLLSRC | RCC_PLLXTPRE | RCC_PLLMULL));
        RCC->CFGR0 |= (uint32_t)(RCC_PLLSRC_HSE | RCC_PLLXTPRE_HSE | RCC_PLLMULL18_EXTEN);
        /* 使能锁相环 */
        RCC->CTLR |= RCC_PLLON;
        while ( (RCC->CTLR & RCC_PLLRDY) == 0 );
        RCC->CFGR0 &= (uint32_t)((uint32_t)~(RCC_SW));
        RCC->CFGR0 |= (uint32_t)RCC_SW_PLL;
        while ( (RCC->CFGR0 & (uint32_t)RCC_SWS) != (uint32_t)0x08 );
    }else{
        /* 外部时钟错误处理 */
        return;
    }
    SystemCoreClock = 144000000;
}

void SystemInit(void){
    RCC->CTLR |= (uint32_t)0x00000001;
    RCC->CFGR0 &= (uint32_t)0xf8ff0000;
    RCC->CFGR0 &= (uint32_t)0xf0ff0000;
    RCC->CTLR &= (uint32_t)0xfef6ffff;
    RCC->CTLR &= (uint32_t)0xfffbffff;
    RCC->CFGR0 &= (uint32_t)0xff80ffff;
    RCC->CTLR &= (uint32_t)0xebffffff;
    RCC->INTR = 0x00ff0000;
    RCC->CFGR2 = 0x00000000;
    RCC->INTR = 0x009f0000;
    Sys_setClock();
}

__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
void SystemCoreClockUpdate(void){
    uint32_t tmp = 0, pllmull = 0, pllsource = 0, pll_6_5 = 0;
    tmp = RCC->CFGR0 & RCC_SWS;
    switch ( tmp ){
        case 0x00:
            SystemCoreClock = HSI_VALUE;
            break;
        case 0x04:
            SystemCoreClock = HSE_VALUE;
            break;
        case 0x08:
            pllmull = RCC->CFGR0 & RCC_PLLMULL;
            pllsource = RCC->CFGR0 & RCC_PLLSRC;
            pllmull = (pllmull >> 18) + 2;
            if ( pllmull == 2 ) pllmull = 18;
            if ( pllmull == 15 ){
                pllmull = 13;
                pll_6_5 = 1;
            }
            if ( pllmull == 16 ) pllmull = 15;
            if ( pllmull == 17 ) pllmull = 16;
            if ( pllsource == 0x00 ){
                if ( EXTEN->EXTEN_CTR & EXTEN_PLL_HSI_PRE ){
                    SystemCoreClock = (HSI_VALUE) * pllmull;
                }else{
                    SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
                }
            }else{
                if ( (RCC->CFGR0 & RCC_PLLXTPRE) != (uint32_t)RESET ){
                    SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
                }else{
                    SystemCoreClock = HSE_VALUE * pllmull;
                }
            }
            if ( pll_6_5 == 1 ) SystemCoreClock = (SystemCoreClock / 2);
            break;
        default:
            SystemCoreClock = HSI_VALUE;
            break;
    }
    tmp = AHBPrescTable[((RCC->CFGR0 & RCC_HPRE) >> 4)];
    SystemCoreClock >>= tmp;
}
